#include <bits/stdc++.h>
#define int long long 
using namespace std;

const int maxn = 13;
const int p = 1e8;
int n;
int dp[maxn][1<<maxn]; // 状压 + 记忆化
int arr[maxn];

vector<int> rows;// 每行可能的情况

bool valid(int val){
	if ((val&(val>>1))==0) {
		return true;
	}
	return false;
}

int dfs(int dep, int row, int last){
	if ((row | arr[dep]) != arr[dep] ) { // 埋伏到空地上了
		return 0;
	}
	
	if ((row&last)!=0) { // 上下相邻了
		return 0;
	}
	
//	cout <<dep<<' '<<row<<'\n';
	
	if (dep==n) {
		return 1;
	}
	
	if (dp[dep][row] != 0) {
		return dp[dep][row];
	}
	
	int ans = 0;
	// 继续往下递归
	for (int r: rows) {
		ans = (ans+dfs(dep+1, r, row))%p;
	}
	
	return dp[dep][row]=ans;
}

void solve(){
	cin >>n;
	
	// 获取每一行的 地形
	for (int i=1;i<=n;i++) {
		for (int j=1;j<=n;j++) {
			int a;
			cin>>a;
			if (a) {
				arr[i] |= (1<<(j-1));				
			}
		}
	}
	
	for (int i=0;i<(1<<n);i++) {
		if (valid(i)) {
			rows.push_back(i);
		}
	}
	
	// dfs 求出所有可能的情况
	int ans = 0;
	
	// 从第一行的 所有可能的情况进行 递归
	for (int row:rows) {
		ans += (ans+dfs(1, row, 0))%p;
	}
	
	cout << ans << '\n';
	
	
	
}

signed main(){
	ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
	solve();
	return 0;
}
